package com.gitee.melin.bee.core.service;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.Instant;
import java.util.List;

import com.gitee.melin.bee.core.hibernate5.HibernateBaseDao;
import com.gitee.melin.bee.core.support.Pagination;
import com.gitee.melin.bee.core.support.PaginationRequest;
import com.gitee.melin.bee.model.BaseEntity;
import com.gitee.melin.bee.model.IEntity;
import com.gitee.melin.bee.core.spring.security.LoginUserDetails;
import org.hibernate.criterion.*;
import org.hibernate.engine.jdbc.LobCreator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;

/**
 * 服务层，公共类
 *
 * @author admin@gmail.com
 */
abstract public class BaseServiceImpl<T extends IEntity, ID extends Serializable> implements BaseService<T, ID>, InitializingBean {
	private static final Logger logger = LoggerFactory.getLogger(BaseServiceImpl.class);

	protected Class<T> entityClass;

	protected String entityName;

	protected boolean isAssignableBaseEntity = true;

	abstract public HibernateBaseDao<T, ID> getHibernateBaseDao();

	private static boolean hasSecurityJar = true;

	static {
		try {
			Class.forName("org.springframework.security.core.Authentication");
		} catch (Throwable e) {
			hasSecurityJar = false;
			logger.warn("spring-security-core.jar not exist");
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {

		Type type = getClass().getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			entityClass = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
			entityName = entityClass.getSimpleName();
			isAssignableBaseEntity = ClassUtils.isAssignable(BaseEntity.class, entityClass);
		}
	}

	@Transactional(rollbackFor = Exception.class, readOnly=true)
	@Override
	public T getEntity(ID id) {
		return this.getHibernateBaseDao().get(id);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findAllEntity() {
		return this.getHibernateBaseDao().loadAll();
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findAllEntity(Projection projection) {
		return this.getHibernateBaseDao().findByNamedParam(projection, new String[]{}, new Object[]{});
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public ID insertEntity(T entity) {
		if(hasSecurityJar) {
			setCreaterAndTime(entity);
		} else {
			setCreateTime(entity);
		}
		return this.getHibernateBaseDao().save(entity);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateEntity(T entity) {
		if(hasSecurityJar) {
			setModifierAndTime(entity);
		} else {
			setUpdateTime(entity);
		}
		this.getHibernateBaseDao().update(entity);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public T mergeEntity(T entity) {
		return this.getHibernateBaseDao().merge(entity);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public T deleteEntity(ID id) {
		return this.getHibernateBaseDao().delete(id);
	}

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteEntity(T entity) {
        this.getHibernateBaseDao().delete(entity);
    }

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void deleteEntity(String key, Object value) {
		String hql = "delete " + entityName + " where " + key + " = :" + key;
		this.deleteOrUpdateByHQL(hql, key, value);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void deleteEntity(String key1, Object value1, String key2, Object value2) {
		String hql = "delete " + entityName + " where " + key1 + " = :" + key1
				+ " and " + key2 + " = :" + key2;
		this.deleteOrUpdateByHQL(hql, key1, value1, key2, value2);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void deleteEntity(String key1, Object value1, String key2, Object value2, String key3, Object value3) {
		String hql = "delete " + entityName + " where " + key1 + " = :" + key1
				+ " and " + key2 + " = :" + key2 + " and " + key3 + " = :" + key3;
		this.deleteOrUpdateByHQL(hql, new String[]{key1, key2, key3}, new Object[]{value1, value2, value3});
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public T logicDeleteEntity(ID id) {
		T entity = this.getEntity(id);
		if(entity instanceof BaseEntity) {
			BaseEntity be = (BaseEntity)entity;
			//be.setDelFlag(1);
			this.updateEntity((T) be);
		}

		return entity;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void bulkDeleteEntity(ID[] ids) {
		for(ID id : ids) {
			this.deleteEntity(id);
		}
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> loadEntities() {
		return this.getHibernateBaseDao().loadAll();
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParam(String propertyName, Object value) {
		return this.getHibernateBaseDao().findByNamedParam(propertyName, value);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParam(Projection projection) {
		return this.getHibernateBaseDao().findByNamedParam(projection, new String[]{}, new Object[]{});
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParam(Projection projection, String propertyName, Object value) {
        return this.getHibernateBaseDao().findByNamedParam(projection, propertyName, value);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParam(String[] columns, String propertyName, Object value) {
        Projection projection = buildProjectionList(columns);
        return this.getHibernateBaseDao().findByNamedParam(projection, propertyName, value);
    }

    private static ProjectionList buildProjectionList(String[] columns) {
		ProjectionList projectionList = null;
        if (columns != null && columns.length > 0) {
			projectionList = Projections.projectionList();
            for (String column : columns) {
                projectionList.add(Projections.property(column).as(column));
            }
        }
        return projectionList;
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParam(String propertyName1, Object value1, String propertyName2, Object value2) {
        return this.getHibernateBaseDao().findByNamedParam(new String[]{propertyName1, propertyName2},
                new Object[]{value1, value2});
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParam(String propertyName1, Object value1, String propertyName2, Object value2, String propertyName3, Object value3) {
        return this.getHibernateBaseDao().findByNamedParam(new String[]{propertyName1, propertyName2, propertyName3},
                new Object[]{value1, value2, value3});
    }

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public T queryByNamedParam(String propertyName, Object value) {
		return this.getHibernateBaseDao().queryByNamedParam(propertyName, value);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public T queryByNamedParam(String propertyName1, Object value1, String propertyName2, Object value2) {
        return this.getHibernateBaseDao().queryByNamedParam(new String[]{propertyName1, propertyName2},
                new Object[]{value1, value2});
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public T queryByNamedParam(String propertyName1, Object value1, String propertyName2, Object value2, String propertyName3, Object value3) {
        return this.getHibernateBaseDao().queryByNamedParam(new String[]{propertyName1, propertyName2, propertyName3},
                new Object[]{value1, value2, value3});
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParam(String[] propertyNames, Object[] values) {
		return this.getHibernateBaseDao().findByNamedParam(propertyNames, values);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParam(Projection projection, String[] propertyNames, Object[] values) {
        return this.getHibernateBaseDao().findByNamedParam(projection, propertyNames, values);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParam(String[] columns, String[] propertyNames, Object[] values) {
        Projection projection = buildProjectionList(columns);
        return this.getHibernateBaseDao().findByNamedParam(projection, propertyNames, values);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public T queryByNamedParam(String[] propertyNames, Object[] values) {
		return this.getHibernateBaseDao().queryByNamedParam(propertyNames, values);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParam(List<String> propertyNames, List<Object> values) {
		return this.getHibernateBaseDao().findByNamedParam(propertyNames.toArray(new String[]{}),
				values.toArray());
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParamAndOrder(String propertyName, Object value, Order ... orders) {
		return this.getHibernateBaseDao().findByNamedParamAndOrder(propertyName, value, orders);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParamAndOrder(String[] propertyNames, Object[] values, Order ... orders) {
		return this.getHibernateBaseDao().findByNamedParamAndOrder(propertyNames, values, orders);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParamAndOrder(Projection projection, String[] propertyNames, Object[] values, Order... orders) {
        return this.getHibernateBaseDao().findByNamedParamAndOrder(projection, propertyNames, values, orders);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByNamedParamAndOrder(String[] columns, String[] propertyNames, Object[] values, Order... orders) {
        Projection projection = buildProjectionList(columns);
        return this.getHibernateBaseDao().findByNamedParamAndOrder(projection, propertyNames, values, orders);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParamAndOrder(List<String> propertyNames, List<Object> values, Order... orders) {
		return this.getHibernateBaseDao().findByNamedParamAndOrder(propertyNames.toArray(new String[]{}),
				values.toArray(), orders);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParamAndOrder(String joinEntity, String propertyName, Object value, Order order) {
		return this.findByNamedParamAndOrder(new String[]{joinEntity}, propertyName, value, order);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParamAndOrder(String[] joinEntitys, String propertyName, Object value, Order order) {
		return this.getHibernateBaseDao().findByNamedParamAndOrder(joinEntitys, new String[]{propertyName},
				new Object[]{value}, new Order[]{order});
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParamAndOrder(String[] joinEntitys, String[] propertyNames, Object[] values, Order order) {
		return this.getHibernateBaseDao().findByNamedParamAndOrder(joinEntitys, propertyNames, values, new Order[]{order});
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findByNamedParamAndOrder(String propertyName, Object value, Order order, int page, int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageByNamedParamAndOrder(propertyName, value, order, offset, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParam(String[] propertyNames, Object[] values, int page, int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findByNamedParam(propertyNames, values, offset, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public List<T> findByNamedParamAndOrder(String[] propertyNames, Object[] values, Order[] orders, int page, int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findByNamedParamAndOrder(propertyNames, values, orders, offset, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPage(int page, int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageByExample(offset, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPage(PaginationRequest<T> paginationRequest) {
		return this.getHibernateBaseDao().findPage(paginationRequest);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageAndOrder(Order[] orders, int page, int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageAndOrderByExample(orders, offset, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageByNamedParam(String joinEntity, String propertyName, Object value,
											  final int page, final int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageByNamedParam(joinEntity, propertyName, value, offset, limit);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageByNamedParam(String propertyName, Object value, final int page, final int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageByNamedParam(propertyName, value, offset, limit);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public Pagination<T> findPageByNamedParam(String propertyName1, Object value1, String propertyName2, Object value2, int page, int limit) {
        int offset = (page - 1) * limit;
        return this.getHibernateBaseDao().findPageByNamedParam(new String[]{propertyName1, propertyName2},
                new Object[]{value1, value2},
                offset, limit);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public Pagination<T> findPageByNamedParamAndOrder(String propertyName1, Object value1, String propertyName2, Object value2, Order order, int page, int limit) {
        int offset = (page - 1) * limit;
        return this.getHibernateBaseDao().findPageByNamedParamAndOrder(new String[]{propertyName1, propertyName2},
                new Object[] {value1, value2},
                new Order[] {order}, offset, limit);
    }

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageByNamedParamAndOrder(String propertyName, Object value, Order order,
													  final int page, final int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageByNamedParamAndOrder(propertyName, value, order, offset, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageByNamedParam(String[] propertyNames, Object[] values, final int page, final int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageByNamedParam(propertyNames, values, offset, limit);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public Pagination<T> findPageByNamedParam(Projection projection, String[] propertyNames, Object[] values, int page, int limit) {
        int offset = (page - 1) * limit;
        return this.getHibernateBaseDao().findPageByNamedParam(projection, propertyNames, values, offset, limit);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public Pagination<T> findPageByNamedParam(String[] columns, String[] propertyNames, Object[] values, int page, int limit) {
        int offset = (page - 1) * limit;
        Projection projection = buildProjectionList(columns);
        return this.getHibernateBaseDao().findPageByNamedParam(projection, propertyNames, values, offset, limit);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageByNamedParam(List<String> propertyNames, List<Object> values, int page, int limit) {
		return this.findPageByNamedParam(propertyNames.toArray(new String[]{}), values.toArray(), page, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageByNamedParamAndOrder(String[] propertyNames, Object[] values, Order[] orders,
													  final int page, final int limit) {
		int offset = (page - 1) * limit;
		return this.getHibernateBaseDao().findPageByNamedParamAndOrder(propertyNames, values, orders, offset, limit);
	}

    @Override
    public Pagination<T> findPageByNamedParamAndOrder(Projection projection, String[] propertyNames, Object[] values, Order[] orders, int page, int limit) {
        int offset = (page - 1) * limit;
        return this.getHibernateBaseDao().findPageByNamedParamAndOrder(projection, propertyNames, values, orders, offset, limit);
    }

    @Override
    public Pagination<T> findPageByNamedParamAndOrder(String[] columns, String[] propertyNames, Object[] values, Order[] orders, int page, int limit) {
        int offset = (page - 1) * limit;
        Projection projection = buildProjectionList(columns);
        return this.getHibernateBaseDao().findPageByNamedParamAndOrder(projection, propertyNames, values, orders, offset, limit);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Pagination<T> findPageByNamedParamAndOrder(List<String> propertyNames, List<Object> values,
													  List<Order> orders, final int page, final int limit) {
		return this.findPageByNamedParamAndOrder(propertyNames.toArray(new String[]{}),
			values.toArray(), orders.toArray(new Order[]{}), page, limit);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Long queryCount() {
		return this.getHibernateBaseDao().findCount();
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Long queryCount(Criterion... criterions) {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
		for (Criterion criterion : criterions) {
			detachedCriteria.add(criterion);
		}
		return this.getHibernateBaseDao().findCountByCriteria(detachedCriteria);
	}

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Long queryCount(String propertyName, Object value) {
		return this.getHibernateBaseDao().findCountByNamedParam(propertyName, value);
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public Long queryCount(String propertyName1, Object value1, String propertyName2, Object value2) {
        return this.getHibernateBaseDao().findCountByNamedParam(new String[]{propertyName1, propertyName2},
                new Object[]{value1, value2});
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public Long queryCount(String propertyName1, Object value1, String propertyName2, Object value2,
                           String propertyName3, Object value3) {
        return this.getHibernateBaseDao().findCountByNamedParam(new String[]{propertyName1, propertyName2, propertyName3},
                new Object[]{value1, value2, value3});
    }

	@Transactional(readOnly=true, rollbackFor = Exception.class)
	@Override
	public Long queryCount(String[] propertyNames, Object[] values) {
		return this.getHibernateBaseDao().findCountByNamedParam(propertyNames, values);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Integer deleteOrUpdateByHQL(final String hql, final String paramName, final Object value) {
		return this.getHibernateBaseDao().deleteOrUpdateByHQL(hql, paramName, value);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Integer deleteOrUpdateByHQL(String hql, String propertyName1, Object value1, String propertyName2, Object value2) {
		return this.getHibernateBaseDao().deleteOrUpdateByHQL(hql, new String[]{propertyName1, propertyName2},
				value1, value2);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Integer deleteOrUpdateByHQL(final String hql, final String[] paramNames, final Object[] values) {
		return this.getHibernateBaseDao().deleteOrUpdateByHQL(hql, paramNames, values);
	}

	@Override
	public LobCreator getLobCreator() {
		return this.getHibernateBaseDao().getLobCreator();
	}

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public T queryByCriterions(Criterion... criterions) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
        for (Criterion criterion : criterions) {
            detachedCriteria.add(criterion);
        }
        return this.getHibernateBaseDao().findByCriteria(detachedCriteria);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public <R> R queryByCriterions(Projection projection, Criterion... criterions) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
        for (Criterion criterion : criterions) {
            detachedCriteria.add(criterion);
        }
        if (projection != null) {
            detachedCriteria.setProjection(projection);
        }
        return this.getHibernateBaseDao().findByCriteria(detachedCriteria);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByCriterions(Criterion... criterions) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
        for (Criterion criterion : criterions) {
            detachedCriteria.add(criterion);
        }
        return this.getHibernateBaseDao().findListByCriteria(detachedCriteria);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public <R> List<R> findByCriterion(Projection projection, Criterion... criterions) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
        for (Criterion criterion : criterions) {
            detachedCriteria.add(criterion);
        }
        if (projection != null) {
            detachedCriteria.setProjection(projection);
        }
        return this.getHibernateBaseDao().findListByCriteria(detachedCriteria);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public List<T> findByCriterions(Order order, Criterion... criterions) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
        for (Criterion criterion : criterions) {
            detachedCriteria.add(criterion);
        }
        if (order != null) {
            detachedCriteria.addOrder(order);
        }
        return this.getHibernateBaseDao().findListByCriteria(detachedCriteria);
    }

    @Transactional(readOnly=true, rollbackFor = Exception.class)
    @Override
    public <R> List<R> findByCriterion(Projection projection, Order order, Criterion... criterions) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
        for (Criterion criterion : criterions) {
            detachedCriteria.add(criterion);
        }
        if (order != null) {
            detachedCriteria.addOrder(order);
        }
        if (projection != null) {
            detachedCriteria.setProjection(projection);
        }
        return this.getHibernateBaseDao().findListByCriteria(detachedCriteria);
    }

    private void setCreaterAndTime(T entity) {
		if (entity instanceof BaseEntity &&
				SecurityContextHolder.getContext().getAuthentication() != null) {

			BaseEntity baseEntity = (BaseEntity) entity;
			baseEntity.setGmtCreated(Instant.now());
			baseEntity.setGmtModified(Instant.now());

            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

            if (principal instanceof LoginUserDetails) {
                LoginUserDetails userDetails = (LoginUserDetails) principal;
				String name = userDetails.getUsername();
				baseEntity.setCreater(name);
				baseEntity.setModifier(name);
			}
		}
	}

	private void setCreateTime(T entity) {
		if (entity instanceof BaseEntity) {
			BaseEntity baseEntity = (BaseEntity) entity;
			baseEntity.setGmtCreated(Instant.now());
			baseEntity.setGmtModified(Instant.now());
		}
	}

	private void setModifierAndTime(T entity) {
		if (entity instanceof BaseEntity &&
				SecurityContextHolder.getContext().getAuthentication() != null) {

			BaseEntity baseEntity = (BaseEntity) entity;
			baseEntity.setGmtModified(Instant.now());

			Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

			if (principal instanceof LoginUserDetails) {
				LoginUserDetails userDetails = (LoginUserDetails) principal;
				String name = userDetails.getUsername();
				baseEntity.setModifier(name);
			}
		}
	}

	private void setUpdateTime(T entity) {
		if (entity instanceof BaseEntity) {
			BaseEntity baseEntity = (BaseEntity) entity;
			baseEntity.setGmtModified(Instant.now());
		}
	}
}
